#include "device_task.h"
#include <protocol/xcom_handler.h>
#include <protocol/xcom_process.h>
#include <dbms/dbms_fd_handler.h>

namespace data_acq {
DeviceTask::DeviceTask(const dbms::Device_t &device)
	: device_(device)
{
}

DeviceTask::~DeviceTask() {}

std::string DeviceTask::ID() { return device_.id(); }

void DeviceTask::OnAcq(const DeviceListener &listener,
	const std::vector<dbms::Funcpoint_t> &funcList,
	const std::vector<libxcom::OpValue> &params)
{
	std::shared_ptr<protocol::XComNode> xcomNode =
		protocol::XComHandler::GetXComInstance()->GetXComNode(
			device_.protoid());
	if (xcomNode == nullptr) {
		HTELINK_LOG_ERR("less for protocol %s", device_.protoid().c_str());
		listener.subscribeException(
			device_, "no protocol," + device_.protoid());
		return;
	}
	if (listener.subscribe == nullptr ||
		listener.subscribeException == nullptr) {
		HTELINK_LOG_ERR("subcribe function not set");
		return;
	}


	protocol::XComProcess xcomProcess(xcomNode, device_.addr());
	dbms::AcqData_t acqData;
	for (auto &func : funcList) {
		if (!xcomProcess.Process(func.id(), listener.communicationCallback,
				params, func.ratio())) {
			listener.subscribeException(
				device_, func.id() + " get data failed");
			continue;
		}
		dbms::AcqItem_t *item = acqData.add_acq_data();
		uint32_t newId =
			dbms::DbmsFdHandler::instance()->SetID(func.id(), PREFIX_FUNCPOINT);
		item->set_funcid(newId);
		libxcom::OpValue v = xcomProcess.GetResult(func.id());
		if (v.IsInteger()) {
			item->set_int_value(v.As<int32_t>());
		} else if (v.IsFloat()) {
			item->set_float_value(v.As<float>());
		} else {
			HTELINK_LOG_ERR("acq(%s) failed", func.id());
			listener.subscribeException(device_, "acq failed");
			continue;
		}
	}
	if (acqData.acq_data_size() > 0) {
		acqData.set_acq_at(time(NULL));
		listener.subscribe(device_, acqData);
	}
}

dbms::Device_t &DeviceTask::GetDevice() { return device_; }

std::vector<dbms::Funcpoint_t> DeviceTask::GetAcqFuncpoints()
{
	std::vector<dbms::Funcpoint_t> functions;
	for (int i = 0; i < device_.funclist_size(); ++i) {
		const dbms::Funcpoint_t &fp = device_.funclist(i);
		if (fp.type() == 1) {
			functions.emplace_back(fp);
		}
	}
	return functions;
}
dbms::Funcpoint_t DeviceTask::GetFuncpoint(int32_t funcId)
{
	dbms::Funcpoint_t funcpoint;
	auto ID = dbms::DbmsFdHandler::instance()->GetID(funcId);

	for (int i = 0; i < device_.funclist_size(); ++i) {
		const dbms::Funcpoint_t &fp = device_.funclist(i);
		if (fp.id() == ID) {
			return fp;
		}
	}
	return funcpoint;
}
} // namespace data_acq
